﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructurePlateHole.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GcmpBuiltInParameterDefinitions.h"
#include "IBaseGraphicsElementShapeComponent.h"
#include "ICalculatorCollection.h"
#include "ICopyStrategyReporter.h"
#include "ICurve3d.h"
#include "IElementOpening.h"
#include "IElementParameterBindings.h"
#include "IElementParameters.h"
#include "IElementParentReporter.h"
#include "IElementPosition.h"
#include "IElementStatus.h"
#include "IElementTransformationComponent.h"
#include "IExternalDataComponent.h"
#include "IFamily.h"
#include "IGenericElement.h"
#include "IGraphicsCurve3d.h"
#include "IInstance.h"
#include "IInstanceType.h"
#include "IModelLine.h"
#include "IOpeningGraphicsElementShapeComponent.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "IParameterOverride.h"
#include "IPolygon.h"
#include "IPositionAssociatedPlane.h"
#include "IPositionPointRelativeHostPoint2d.h"
#include "IRegenerator.h"
#include "IRegeneratorDataIdCreator.h"
#include "IStructureInstanceBuildingStoreyData.h"
#include "IStructurePlate.h"
#include "InstancePlacementTypes.h"
#include "LevelUtils.h"
#include "ProfileUsedModelLineUtils.h"
#include "StructureFloor.h"
#include "StructureFloorHoleGraphicsElementShapeBehavior.h"
#include "StructureInstanceHoleValidator.h"
#include "StructureInstanceLevelUtils.h"
#include "StructureInstanceUtils.h"
#include "StructurePlateHoleCalculators.h"
#include "StructurePlateHoleInput.h"
#include "StructureProfileInstanceUtils.h"
#include "StructureRaftFoundation.h"
#include "IGeometryRelationshipComponent.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace gcmp
{
    // 自定义参数行为
    // 自定义顶部标高的行为：修改可见性
    class StructurePlateHoleLevelOverride : public NdbObjectSchematic, public IParameterOverride
    {
        DBOBJECT_DATA_BEGIN_AND_QUICK_CAST_FROM(gcmp, StructurePlateHoleLevelOverride, gcmp::NdbObjectSchematic, 6BCAB6E2 - EE5B - 4E88 - 8DA5 - 1F1BE385BDF6, gmstructure, gcmp::IParameterOverride)
        DBOBJECT_DATA_END
    public:
        virtual UniIdentity GetUniIdentity() const override { return PARAMETER_UID(TopAssociatedLevelBuiltInParameter); }
        virtual bool ShouldOverrideIsModifiable() const override { return false; }
        virtual bool IsModifiable() const override { return true; }
        virtual bool ShouldOverrideIsUserVisible() const override { return true; }   // 这里返回true表示可以用户修改
        virtual bool IsUserVisible() const override { return false; }                   // 这里返回false表示不可见
        virtual bool ShouldOverrideGetName() const override { return false; }
        virtual std::wstring GetName() const override { return L""; }
        virtual bool ShouldOverrideGetValidator() const override { return false; }
        virtual const IParameterValidator * GetValidator() const override { return nullptr; }

        virtual IElement* GetOwnerElement() override { return nullptr; }
        virtual const IElement* GetOwnerElement() const override { return nullptr; }
        virtual bool SetOwnerElement(IElement* pElement) override { return true; }
    public: //实现NdbObject接口
        virtual NdbObject* GetTopOwnerObject() const override
        {
            return nullptr;
        }
    };

    DBOBJECT_DATA_DEFINE(StructurePlateHoleLevelOverride)
    {
    }

    // 自定义顶部偏移的行为：修改可见性
    class StructurePlateHoleTopOffsetOverride :public NdbObjectSchematic, public IParameterOverride
    {
        DBOBJECT_DATA_BEGIN_AND_QUICK_CAST_FROM(gcmp, StructurePlateHoleTopOffsetOverride, gcmp::NdbObjectSchematic, 261D63D6 - 61CA - 4AB5 - B740 - 093259312E17, gmstructure, gcmp::IParameterOverride)
        DBOBJECT_DATA_END
    public:
        virtual UniIdentity GetUniIdentity() const override { return PARAMETER_UID(TopOffsetBuiltInParameter); }
        virtual bool ShouldOverrideIsModifiable() const override { return false; }
        virtual bool IsModifiable() const override { return true; }
        virtual bool ShouldOverrideIsUserVisible() const override { return true; }    // 这里返回true表示可以用户修改
        virtual bool IsUserVisible() const override { return false; }                    // 这里返回false表示不可见
        virtual bool ShouldOverrideGetName() const override { return false; }
        virtual std::wstring GetName() const override { return L""; }
        virtual bool ShouldOverrideGetValidator() const override { return false; }
        virtual const IParameterValidator * GetValidator() const override { return nullptr; }

        virtual IElement* GetOwnerElement() override { return nullptr; }
        virtual const IElement* GetOwnerElement() const override { return nullptr; }
        virtual bool SetOwnerElement(IElement* pElement) override { return true; }
    public: //实现NdbObject接口
        virtual NdbObject* GetTopOwnerObject() const override
        {
            return nullptr;
        }
    };

    DBOBJECT_DATA_DEFINE(StructurePlateHoleTopOffsetOverride)
    {
    }

    // 自定义板洞所属楼层的行为：所属楼层是否可修改
    class StructurePlateHoleStoreyOverride :public NdbObjectSchematic, public IParameterOverride
    {
        DBOBJECT_DATA_BEGIN_AND_QUICK_CAST_FROM(gcmp, StructurePlateHoleStoreyOverride, gcmp::NdbObjectSchematic, 95AAA396 - A875 - 4AF4 - ACE0 - AAAE76FFB56E, gmstructure, gcmp::IParameterOverride)
        DBOBJECT_DATA_END
    public:
        virtual UniIdentity GetUniIdentity() const override { return PARAMETER_UID(BuildingStoreyBuiltInParameter); }
        virtual bool ShouldOverrideIsModifiable() const override { return true; }
        virtual bool IsModifiable() const override { return false; }
        virtual bool ShouldOverrideIsUserVisible() const override { return false; }
        virtual bool IsUserVisible() const override { return true; }
        virtual bool ShouldOverrideGetName() const override { return false; }
        virtual std::wstring GetName() const override { return L""; }
        virtual bool ShouldOverrideGetValidator() const override { return false; }
        virtual const IParameterValidator * GetValidator() const override { return nullptr; }

        virtual IElement* GetOwnerElement() override { return nullptr; }
        virtual const IElement* GetOwnerElement() const override { return nullptr; }
        virtual bool SetOwnerElement(IElement* pElement) override { return true; }

    public: //实现NdbObject接口
        virtual NdbObject* GetTopOwnerObject() const override
        {
            return nullptr;
        }
    };

    DBOBJECT_DATA_DEFINE(StructurePlateHoleStoreyOverride)
    {
    }
}

DEFINE_STRUCTURE_INSTANCE_METHODS(StructurePlateHole)
IMPLEMENT_REGEN_FUNCTIONS(gcmp, StructurePlateHole, PositionValidity)

DBOBJECT_DATA_DEFINE(StructurePlateHole)
{
    m_pOwnerElement = nullptr;
    SetConcreteStrengthGrade__(ConcreteStrengthGradeType::CSG_C30);
    SetPositionValidity__(true);
}

StructurePlateHole* StructurePlateHole::Create(const StructurePlateHoleGeometryInput* pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pInput->Document;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    const IPolygon* pPolygon = pInput->ProfilePolygon.get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPolygon, L"pPolygon为空",L"GDMPLab",L"2024-03-30");

    ElementId associatedPlaneId = pInput->AssociatedPlaneId;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(associatedPlaneId.IsValid(), L"associatedPlaneId无效",L"GDMPLab",L"2024-03-30");

    OwnerPtr<StructurePlateHoleElementInput> pElementInput = NEW_AS_OWNER_PTR(StructurePlateHoleElementInput);

    std::vector<IModelLine*> profileCurves;
    bool bOk = StructureProfileInstanceUtils::GenerateProfileCurvesFromPolygon(pDoc, pPolygon, associatedPlaneId, profileCurves);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"ProfileCurves生成失败",L"GDMPLab",L"2024-03-30");

    // 继承自StructureInstanceInput的参数
    pElementInput->Document = pDoc;
    pElementInput->FamilyId = pInput->FamilyId;
    pElementInput->InstanceTypeId = pInput->InstanceTypeId;
    pElementInput->AssociatedPlaneId = associatedPlaneId;
    pElementInput->StoreyId = pInput->StoreyId;
    pElementInput->CreationOption = pInput->CreationOption;
    pElementInput->CanBeShared = pInput->CanBeShared;
    pElementInput->Visible = pInput->Visible;
    // StructurePlateHoleElementInput的参数
    pElementInput->ProfileCurves = profileCurves;
    pElementInput->HostId = pInput->HostId;

    StructurePlateHole* pPlateHole = StructurePlateHole::Create(pElementInput.get());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPlateHole, L"pStructurePlateHole为空",L"GDMPLab",L"2024-03-30");

    return pPlateHole;
}

StructurePlateHole* StructurePlateHole::Create(const StructurePlateHoleElementInput* pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pInput->Document;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstanceType* pInstanceType = quick_cast<IInstanceType>(pDoc->GetElement(pInput->InstanceTypeId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstanceType, L"pInstanceType为空",L"GDMPLab",L"2024-03-30");

    IInstance* pInstance = pInstanceType->CreateInstance(L"板洞实例", pInput->CanBeShared, pInput->CreationOption, pInput->IsCreateGeometryRelationshipComponent);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<StructurePlateHoleValidator> pPlateHoleValidator = NEW_AS_OWNER_PTR(StructurePlateHoleValidator);
    IBaseGraphicsElementShapeComponent* pBaseShapeComponent = pInstance->GetBaseGraphicsElementShapeComponent();
    DBG_WARN_AND_RETURN_UNLESS(pBaseShapeComponent, nullptr, L"pBaseShapeComponent为空",L"GDMPLab",L"2024-03-30");

    pBaseShapeComponent->SetValidator(TransferOwnership(pPlateHoleValidator));
    // 设置主体构件
    IInstance* pHostInstance = quick_cast<IInstance>(pDoc->GetElement(pInput->HostId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pHostInstance, L"pHostInstance为空",L"GDMPLab",L"2024-03-30");
    pInstance->SetHostInstanceId(pInput->HostId);

    // 将板洞注册成外部数据
    OwnerPtr<StructurePlateHole> opPlateHole = NEW_AS_OWNER_PTR(StructurePlateHole);
    StructurePlateHole* pPlateHole = opPlateHole.get();
    pPlateHole->SetOwnerElement(pInstance);
    if (IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        pExternalDataComponent->RegisterExternalData(pPlateHole->GetClassSchema()->GetName(), TransferOwnership(opPlateHole));
    }

    std::vector<IModelLine*> profileCurves = pInput->ProfileCurves;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(!profileCurves.empty(), L"profileCurves为空",L"GDMPLab",L"2024-03-30");

    // 更新板洞轮廓线
    bool bOk = pPlateHole->UpdatePlateHoleProfiles(profileCurves);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"更新板洞轮廓线失败",L"GDMPLab",L"2024-03-30");

    // 洞口的所属楼层（与宿主保持一致，关联变化通过计算器实现）
    const ElementId storeyLevelId = StructureInstanceLevelUtils::GetInstanceStoreyLevelId(pHostInstance);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(storeyLevelId != ElementId::InvalidID, L"pStoreyLevel无效",L"GDMPLab",L"2024-03-30");
    bOk = StructureInstanceLevelUtils::CreateInstanceStoreyLevel(pDoc, pInstance->GetElementId(), storeyLevelId);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"设置板洞的StoreyLevel失败",L"GDMPLab",L"2024-03-30");

    double topOffset = 0.0;
    bOk = StructureInstanceUtils::GetInstanceTopOffset(pHostInstance, topOffset);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"获取顶部标高偏移失败",L"GDMPLab",L"2024-03-30");

    double levelElevation = 0.0;
    bOk = LevelUtils::GetLevelElevation(pDoc, IElementPosition::GetAssociatedPlaneId(pHostInstance), levelElevation);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"获取楼层高度失败",L"GDMPLab",L"2024-03-30");

    FOR_EACH(pModelLine, profileCurves)
    {
        //设置轮廓线在基准面上的偏移
        IGenericElement* pGenericElement = quick_cast<IGenericElement> (pModelLine->GetOwnerElement());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElement, L"获取pGenericElement为空！",L"GDMPLab",L"2024-03-30");

        IElementPosition* pModelLineElementPosition = pGenericElement->GetElementPosition();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelLineElementPosition, L"获取pElementPosition为空！",L"GDMPLab",L"2024-03-30");

        IPositionAssociatedPlane* pAssociatedPlane = pModelLineElementPosition->GetPositionAssociatedPlane();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pAssociatedPlane, L"获取pAssociatedPlane为空！",L"GDMPLab",L"2024-03-30");

        pAssociatedPlane->SetBasePlaneOffset(topOffset + levelElevation);
    }

    OwnerPtr<IPolygon> opPolygon;
    Coordinate3d polygonCoord(Vector3d(0, 0, 0), Vector3d::UnitX, Vector3d::UnitY);
    bOk = StructureProfileInstanceUtils::GeneratePolygonFromProfileCurves(profileCurves, opPolygon, polygonCoord);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"Polygon生成失败",L"GDMPLab",L"2024-03-30");

    // 创建板洞的定位方式
    IElementPosition::CreatePointRelativeHostPoint2dOnSingleAssociatedPlanePositionBehavior(pInstance, IElementPosition::GetAssociatedPlaneId(pHostInstance),
        polygonCoord.GetOrigin(), polygonCoord.GetX(), polygonCoord.GetY());

    if (opPolygon)
    {
        bool bOk = StructureProfileInstanceUtils::SetProfileByCurveArray(opPolygon.get(), polygonCoord, pInstance);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"设置洞口轮廓线失败",L"GDMPLab",L"2024-03-30");
    }

    // 确认板洞的放置类型
    OwnerPtr<IParameter> paramPlacementType = ELEMENT_PARAMETER(pInstance, InstancePlacementTypeBuiltInParamter);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(IParameter::IsValidParameter(paramPlacementType), L"placementType参数获取失败",L"GDMPLab",L"2024-03-30");
    InstancePlacementTypes placementType = (InstancePlacementTypes)paramPlacementType->GetValueAsInt();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(InstancePlacementTypes::FamilyBasedOnProfile == placementType, L"板洞的放置类型不正确",L"GDMPLab",L"2024-03-30");
    
    // 设置模型线关联的构件
    ProfileUsedModelLineUtils::SetAssociatedInstanceIdForModelLines(profileCurves, pInstance->GetElementId());

    // 将模型线从世界坐标系转换到楼板的局部坐标系，这样以后就可以根据楼板PositionHelper位置更新模型线的位置
    {
        const IElementPosition *posBehavior = pInstance->GetElementPosition();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"posBehavior为空",L"GDMPLab",L"2024-03-30");

        Matrix4d mat = posBehavior->ComputeLocalToWorldCoordinateSystemTransformMatrix();
        bool bOk = mat.MakeInverse();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"MakeInverse失败",L"GDMPLab",L"2024-03-30");

        FOR_EACH(pModelLine, profileCurves)
        {
            pModelLine->GetOwnerElement()->GetStatus()->SetIsVisible(false);
            pModelLine->GetOwnerElement()->GetElementTransformationComponent()->Transform(mat);
        }
    }

    // 板洞厚度
    {
        // 用楼板/筏板的厚度更新洞口扣减体
        OwnerPtr<IParameter> thicknessParamInOpening;
        if (pInstance->GetElementParameters()->HasParameterByUid(PARAMETER_UID(PlateHoleThicknessBuiltInParameter)))
        {
            thicknessParamInOpening = ELEMENT_PARAMETER(pInstance, PlateHoleThicknessBuiltInParameter);
        }
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(IParameter::IsValidParameter(thicknessParamInOpening), L"pInstance中没有预期参数",L"GDMPLab",L"2024-03-30");

        // 宿主是楼板：将板洞厚度绑定到楼板的补偿高度上，以保证板洞能够击穿楼板
        // 宿主是筏板：只需绑定筏板厚度
        // 宿主是楼板：需要定制板洞的Grep
        // 宿主是筏板：根据BaseGrep计算器计算
        OwnerPtr<IParameter> paraHostInstanceHeight;
        if (pHostInstance->GetBasicInformation()->GetCategoryUid().HasSameValue(BuiltInCategoryUniIdentities::BICU_STRUCTURE_FLOOR))
        {
            paraHostInstanceHeight = ELEMENT_PARAMETER(pHostInstance, FloorCompensationThicknessBuiltInParameter);
            double holeThickness = 0.0;
            if (IParameter::IsValidParameter(paraHostInstanceHeight))
            {
                holeThickness = paraHostInstanceHeight->GetValueAsDouble();
            }
            thicknessParamInOpening->SetValueAsDouble(holeThickness);
            pInstance->GetElementParameters()->SetParameter(thicknessParamInOpening.get());
            OwnerPtr<StructureFloorHoleGraphicsElementShapeBehavior> opGRepBehavior = NEW_AS_OWNER_PTR(StructureFloorHoleGraphicsElementShapeBehavior, pInstance);
            pInstance->AddGraphicsElementShapeCustomizableBehavior(TransferOwnership(opGRepBehavior));
        }
        else if (pHostInstance->GetBasicInformation()->GetCategoryUid().HasSameValue(BuiltInCategoryUniIdentities::BICU_STRUCTURE_FOUNDATION))
        {
            paraHostInstanceHeight = ELEMENT_PARAMETER(pHostInstance->GetBasicInformation()->GetType(), RaftFoundationThicknessBuiltInParameter);
            IElementParameters* pElementParameters = pInstance->GetElementParameters();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementParameters, L"pElementParameters为空",L"GDMPLab",L"2024-03-30");

            IElementParameterBindings* pElementParameterBindings = pElementParameters->GetElementParameterBindings();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementParameterBindings, L"pElementParameterBindings为空",L"GDMPLab",L"2024-03-30");

            bool bOk = pElementParameterBindings->AddParameterBinding(
                thicknessParamInOpening->GetParameterDefinitionId(), 
                paraHostInstanceHeight->GetParameterDefinitionId(),
                pHostInstance->GetElementId(), true);
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"参数绑定失败",L"GDMPLab",L"2024-03-30");

            IGeometryRelationshipComponent* pGeometryRepCpt = pInstance->GetGeometryRelationshipComponent();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pGeometryRepCpt != nullptr, L"无效的指针",L"GDMPLab",L"2024-03-30");
            IOpeningGraphicsElementShapeComponent* pCutterGRepComponent = pGeometryRepCpt->GetOpeningGraphicsElementShapeComponent();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCutterGRepComponent != nullptr, L"无效的指针",L"GDMPLab",L"2024-03-30");
            pCutterGRepComponent->SetShouldCalculateIntersectingGraphicsElementShape(true);
        }
        else
        {
            DBG_WARN(L"无效的Category",L"GDMPLab",L"2024-03-30");
        }
    }
    // 建立打洞关系
    IElementOpening::Create(pDoc, pInstance->GetElementId(), pHostInstance->GetElementId());

    // 自定义参数行为
    {
        IElementParameters * pElementParameters = pInstance->GetElementParameters();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementParameters, L"参数行为为空",L"GDMPLab",L"2024-03-30");
 
        // 修改参数可见性
        pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(StructurePlateHoleLevelOverride));
        pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(StructurePlateHoleTopOffsetOverride));
        pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(StructurePlateHoleStoreyOverride));
    }

    // 设置板洞的可见性
    IElementStatus* pStatus = pInstance->GetStatus();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    pStatus->SetIsVisible(pInput->Visible);

    return pPlateHole;
}

StructurePlateHole* StructurePlateHole::Edit(const StructurePlateHoleEditGeometryInput* pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pInput->Document;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    const IPolygon* pPolygon = pInput->ProfilePolygon.get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPolygon, L"pPolygon为空",L"GDMPLab",L"2024-03-30");

    ElementId instanceId = pInput->InstanceId;
    IInstance* pInstance = quick_cast<IInstance>(pDoc->GetElement(instanceId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    const IElementPosition* posBehavior = pInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"posBehavior为空",L"GDMPLab",L"2024-03-30");
    const IPositionAssociatedPlane* posAssociatedPlane = quick_cast<const IPositionAssociatedPlane>(posBehavior->GetPositionAssociatedPlane());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posAssociatedPlane, L"posAssociatedPlane为空",L"GDMPLab",L"2024-03-30");
    ElementId associatedPlaneId = posAssociatedPlane->GetBasePlaneElementId();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(associatedPlaneId.IsValid(), L"associatedPlaneId无效",L"GDMPLab",L"2024-03-30");

    std::vector<IModelLine*> profileCurves;
    bool bOk = StructureProfileInstanceUtils::GenerateProfileCurvesFromPolygon(pDoc, pPolygon, associatedPlaneId, profileCurves);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"ProfileCurves生成失败",L"GDMPLab",L"2024-03-30");
    
    OwnerPtr<StructurePlateHoleEditElementInput> pElementInput = NEW_AS_OWNER_PTR(StructurePlateHoleEditElementInput);
    pElementInput->Document = pDoc;
    pElementInput->InstanceId = instanceId;
    pElementInput->ProfileCurves = profileCurves;

    StructurePlateHole* pPlateHole = StructurePlateHole::Edit(pElementInput.get());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPlateHole, L"pStructurePlateHole为空",L"GDMPLab",L"2024-03-30");

    return pPlateHole;
}

StructurePlateHole* StructurePlateHole::Edit(const StructurePlateHoleEditElementInput* pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pInput->Document;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    ElementId instanceId = pInput->InstanceId;
    IInstance* pInstance = quick_cast<IInstance>(pDoc->GetElement(instanceId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    const IElementPosition* posBehavior = pInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"posBehavior为空",L"GDMPLab",L"2024-03-30");

    const IPositionPointRelativeHostPoint2d* posPointRelativeHostPoint2d = quick_cast<const IPositionPointRelativeHostPoint2d>(posBehavior->GetPositionGeometry());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posPointRelativeHostPoint2d, L"posPointRelativeHostPoint2d为空",L"GDMPLab",L"2024-03-30");

    // 获取板洞数据
    StructurePlateHole* pPlateHole = StructurePlateHole::Get(pInstance);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPlateHole, L"获取板洞数据失败",L"GDMPLab",L"2024-03-30");

    std::vector<IModelLine*> profileCurves = pInput->ProfileCurves;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(!profileCurves.empty(), L"profileCurves为空",L"GDMPLab",L"2024-03-30");

    // 更新板洞轮廓线
    bool bOk = pPlateHole->UpdatePlateHoleProfiles(profileCurves);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"更新板洞轮廓线失败",L"GDMPLab",L"2024-03-30");

    std::vector<OwnerPtr<ICurve3d>> profileICurvesOwner;// 外圈轮廓
    std::vector<const ICurve3d*> profileICurves;
    for (auto& pModelLine : profileCurves)
    {
        OwnerPtr<ICurve3d> opCurve3d = pModelLine->GetGeometryCurve();
        profileICurves.push_back(opCurve3d.get());
        profileICurvesOwner.push_back(TransferOwnership(opCurve3d));
    }

    StructureProfileInstanceUtils::MirrorProfileCoordinate(pInstance, profileICurvesOwner);

    // 保持原有插入点的位置
    Vector3d insertPt = posPointRelativeHostPoint2d->GetWorldOrigin();
    Coordinate3d baseCoord(insertPt, posPointRelativeHostPoint2d->GetDirectionX(), posPointRelativeHostPoint2d->GetDirectionY());
    OwnerPtr<IPolygon> opPolygon = StructureProfileInstanceUtils::CalculateProfilePolygon(profileICurves, baseCoord);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opPolygon, L"Polygon生成失败",L"GDMPLab",L"2024-03-30");

    // 更新轮廓线
    bOk = StructureProfileInstanceUtils::SetProfileByCurveArray(opPolygon.get(), baseCoord, pInstance);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"更新轮廓线失败",L"GDMPLab",L"2024-03-30");

    // 保存模型线
    {
        Matrix4d mat = posBehavior->ComputeLocalToWorldCoordinateSystemTransformMatrix();
        bool bOk = mat.MakeInverse();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"MakeInverse失败",L"GDMPLab",L"2024-03-30");

        FOR_EACH(pModelLine, profileCurves)
        {
            pModelLine->GetOwnerElement()->GetStatus()->SetIsVisible(false);
            pModelLine->GetOwnerElement()->GetElementTransformationComponent()->Transform(mat);
        }
    }

    IElementStatus* pStatus = pInstance->GetStatus();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    pStatus->SetIsVisible(true);

    return pPlateHole;
}

StructurePlateHole* StructurePlateHole::Get(IInstance* pInstance)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    if (IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        IExternalData *pData = pExternalDataComponent->FindExternalData(StructurePlateHole::GetStaticClassSchema()->GetName());
        if (!pData)
        {
            return nullptr;
        }
        return quick_cast<StructurePlateHole>(pData);
    }
    return nullptr;
}

const StructurePlateHole* StructurePlateHole::Get(const IInstance* pInstance)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    if (const IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        const IExternalData *pData = pExternalDataComponent->FindExternalData(StructurePlateHole::GetStaticClassSchema()->GetName());
        if (!pData)
        {
            return nullptr;
        }
        return quick_cast<StructurePlateHole>(pData);
    }
    return nullptr;
}

NdbObject* StructurePlateHole::GetTopOwnerObject() const
{
    if (!GetDocument())
    {
        return nullptr;
    }

    return quick_cast<NdbObject>(GetDocument()->GetElement(GetOwnerElementId()));
}

void StructurePlateHole::UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds)
{
    FOR_EACH(id, deletedElementIds)
    {
        auto it = std::find(GetProfileIdsFW__().begin(), GetProfileIdsFW__().end(), id);
        if (it != GetProfileIdsFW__().end())
        {
            GetProfileIdsFW__().erase(it);
        }
    }
}

void StructurePlateHole::ReportParents(IElementParentReporter& reporter) const
{
    FOR_EACH(id, GetProfileIds__())
    {
        reporter.ReportWeak(id);
    }
}

DECLARE_CALCULATOR_CREATOR(PlateHoleAssociatedLevelCalculator)
void StructurePlateHole::GetCalculators(ICalculatorCollection * calculators) const
{
    const IElement* pElement = this->GetOwnerElement();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
    ElementId plateHoleId = pElement->GetElementId();
    const IInstance* pPlateHoleInstance = dynamic_cast<const IInstance*>(GetDocument()->GetElement(plateHoleId));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pPlateHoleInstance, L"pPlateHoleInstance为空",L"GDMPLab",L"2024-03-30");
    const IStructureInstanceBuildingStoreyData* pPlateHoleStoreyData = IStructureInstanceBuildingStoreyData::Get(pPlateHoleInstance);    
    DBG_WARN_AND_RETURN_VOID_UNLESS(pPlateHoleStoreyData, L"pPlateHoleStoreyData为空",L"GDMPLab",L"2024-03-30");
    RegenDataId plateHoleStoreyDataId = pPlateHoleStoreyData->GetBuildingStoreyIdRdId();
    ADD_CALCULATOR(PlateHoleAssociatedLevelCalculator, GetDocument(), plateHoleStoreyDataId);
}

void StructurePlateHole::ReportParameterDefinitions(std::vector<int>* pParamDefIds) const
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParamDefIds != nullptr, L"pParamDefUids为空",L"GDMPLab",L"2024-03-30");
}

OwnerPtr<IParameter> StructurePlateHole::GetNativeParameter(int paramDefId) const
{
    return nullptr;
}

bool StructurePlateHole::SetNativeParameter(const IParameter *param, std::wstring* errorMsg/* = nullptr*/)
{
    return false;
}

bool StructurePlateHole::IsParameterModifiable(int paramDefId) const
{
    return false;
}

void StructurePlateHole::Report(const ICopyContext & copyContext, ICopyStrategyReporter& reporter) const
{
    reporter.ReportToCopy(GetOwnerElementId());

    FOR_EACH(id, GetProfileIds__())
    {
        reporter.ReportToCopy(id);
    }
}

bool gcmp::StructurePlateHole::Transform(const Matrix4d & matrix)
{
    // 该段代码只对平台GBMP起效
    if (!matrix.IsMirror())
        return true;

    Matrix4d matMirrorLocal;
    matMirrorLocal.MakeMirror(Vector3d::Zero, Vector3d::UnitY);

    IDocument* pDoc = GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    // 对板洞边缘上的轮廓线进行镜像操作，使其与板洞边缘一致
    auto profileIds = GetProfileIds();
    FOR_EACH(id, profileIds)
    {
        IElement* pProfileLineElement = pDoc->GetElement(id);
        if (pProfileLineElement)
        {
            IElementPosition *pElementPosition = pProfileLineElement->GetElementPosition();
            DBG_WARN_AND_CONTINUE_UNLESS(pElementPosition, L"pElementPosition 为空",L"GDMPLab",L"2024-03-30");
            if (!pElementPosition->Transform(matMirrorLocal))
                return false;
        }
    }
    return true;
}

IDocument* StructurePlateHole::GetDocument() const
{
    return m_pOwnerElement ? m_pOwnerElement->GetDocument() : nullptr;
}

ElementId StructurePlateHole::GetOwnerElementId() const
{
    return m_pOwnerElement ? m_pOwnerElement->GetElementId() : ElementId::InvalidID;
}

OwnerPtr<IPolygon> StructurePlateHole::GetProfilePolygon() const
{
    IDocument* pDoc = GetDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    std::vector<ElementId> profileIds = GetProfileIds();
    std::vector<IModelLine*> profileCurves;
    bool bOk = ProfileUsedModelLineUtils::GetModelLinesUsedForProfileByElementIds(pDoc, profileIds, profileCurves);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"获取ModelLinesUsedForProfile失败",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IPolygon> opPolygon;
    Coordinate3d polygonCoord(Vector3d(0, 0, 0), Vector3d::UnitX, Vector3d::UnitY);
    bOk = StructureProfileInstanceUtils::GeneratePolygonFromProfileCurves(profileCurves, opPolygon, polygonCoord);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"Polygon生成失败",L"GDMPLab",L"2024-03-30");

    // 将轮廓线从局部坐标系转换回世界坐标系
    const IElementPosition *pElementPosition = m_pOwnerElement->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementPosition, L"pElementPosition为空",L"GDMPLab",L"2024-03-30");
    Matrix4d mat = pElementPosition->ComputeLocalToWorldCoordinateSystemTransformMatrix();
    opPolygon->Transform(mat);

    return opPolygon;
}

const IStructurePlate* StructurePlateHole::GetHost() const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pOwnerElement, L"m_pOwnerElement为空",L"GDMPLab",L"2024-03-30");

    ElementId plateId = m_pOwnerElement->GetHostElementId();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(plateId.IsValid(), L"plateId无效",L"GDMPLab",L"2024-03-30");

    IElement* pElement = GetDocument()->GetElement(plateId);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");

    const IInstance* pPlateInstance = quick_cast<IInstance>(pElement);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPlateInstance, L"pPlateInstance为空",L"GDMPLab",L"2024-03-30");
    
    const IExternalData *pData = nullptr;
    const IExternalData* pData1 = nullptr;
    if (const IExternalDataComponent * pExternalDataComponent = pPlateInstance->GetExternalDataComponent())
    {
        pData = pExternalDataComponent->FindExternalData(StructureFloor::GetStaticClassSchema()->GetName());
        pData1 = pExternalDataComponent->FindExternalData(StructureRaftFoundation::GetStaticClassSchema()->GetName());
    }
    if (pData)
    {
        return quick_cast<StructureFloor>(pData);
    }
    else if (pData1)
    {
        return quick_cast<StructureRaftFoundation>(pData1);
    }
    else
    {
        DBG_WARN(L"不支持的板类型",L"GDMPLab",L"2024-03-30");
    }
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(false, L"pStructurePlate为空",L"GDMPLab",L"2024-03-30");

    return nullptr;
}

bool StructurePlateHole::UpdatePlateHoleProfiles(const std::vector<IModelLine*> profileCurves)
{
    std::vector<ElementId> profileIds;
    FOR_EACH(pModelLine, profileCurves)
    {
        profileIds.push_back(pModelLine->GetOwnerElement()->GetElementId());
    }
    this->SetProfileIds__(profileIds);

    return true;
}
